/**
* @file lcd_if_spi4.c
* @brief  lcd interface for spi4w
* @details 
* @author huangbin
* @version V1.0.0
* @date 2025-04-30
* @copyright All documents are copyrighted by Shenzhen Xinlongwei Technology Co., LTD.
*            They may not be used for commercial purposes without permission
*/
/*
lcd1的 spi4 接口抽象文件，所有上层不同驱动ic共享此接口文件。
接口类型：4线spi:rs,cs,clk,data + reset
*/
#include "inc.h"
#include	"lcd_if_spi4.h"
static uint16_t LcdXOffset,LcdYOffset;

void lcd_hardware_spi_init(void);
#define USE_HARDWARE_SPI 1  //如果定义宏，使用硬件spi驱动
static void Lcd_Spi4_IoInit(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
    
	RCC_APB2PeriphClockCmd(LCD_SPI4_ALL_CLK,ENABLE);
    
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
	GPIO_InitStructure.GPIO_Pin = LCD_SPI4_CS_PIN; 
    GPIO_Init ( LCD_SPI4_CS_PORT, & GPIO_InitStructure );
    
	GPIO_InitStructure.GPIO_Pin = LCD_SPI4_DC_PIN; 
    GPIO_Init ( LCD_SPI4_DC_PORT, & GPIO_InitStructure );
    
	GPIO_InitStructure.GPIO_Pin = LCD_SPI4_RESET_PIN; 
    GPIO_Init ( LCD_SPI4_RESET_PORT, & GPIO_InitStructure );

	GPIO_InitStructure.GPIO_Pin = LCD_SPI4_BK_PIN; 
    GPIO_Init ( LCD_SPI4_BK_PORT, & GPIO_InitStructure );
#ifdef USE_HARDWARE_SPI  
    lcd_hardware_spi_init();
#else    
	GPIO_InitStructure.GPIO_Pin = LCD_SPI4_CLK_PIN; 
    GPIO_Init ( LCD_SPI4_CLK_PORT, & GPIO_InitStructure );
    
	GPIO_InitStructure.GPIO_Pin = LCD_SPI4_MOSI_PIN; 
    GPIO_Init ( LCD_SPI4_MOSI_PORT, & GPIO_InitStructure );
#endif    

	LCD_SPI4_RESET_HIGH();
	LCD_SPI4_CS_HIGH();
    LCD_SPI4_BK_OFF();
	DebugPrintf("LCD init spi4 io!\r\n");	
}
//硬件spi初始化
void lcd_hardware_spi_init(void)
{
 	GPIO_InitTypeDef GPIO_InitStructure;
	SPI_InitTypeDef  SPI_InitStructure;

	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA, ENABLE );
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_SPI1,  ENABLE );
 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//设置SPI工作模式:设置为主SPI
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//设置SPI的数据大小:SPI发送接收8位帧结构
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//串行同步时钟的空闲状态为高电平
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//串行同步时钟的第二个跳变沿（上升或下降）数据被采样
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSS信号由硬件（NSS管脚）还是软件（使用SSI位）管理:内部NSS信号有SSI位控制
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;		//定义波特率预分频的值
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
	SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式
	SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
 
	SPI_Cmd(SPI1, ENABLE); //使能SPI外设    
}

#ifdef USE_HARDWARE_SPI
static void Lcd_Spi4_WriteByte(uint8_t d)
{
    // 等待发送缓冲区为空
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) __NOP();
    // 发送数据
    SPI_I2S_SendData(SPI1, d);
    // 等待发送完成
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) != RESET) __NOP();
}
#else
//通过 spi4 接口写一个字节数据
static void Lcd_Spi4_WriteByte(uint8_t d)
{
	uint32_t i,spidat;
	
	spidat = d;
	for(i=0; i<8; i++)			
	{  
		LCD_SPI4_CLK_LOW();
		if( (spidat&0x0080)!=0 ) 
			LCD_SPI4_MOSI_HIGH();
		else 
			LCD_SPI4_MOSI_LOW();
		spidat <<= 1;
//		for(uint16_t j = 0;j < 45;j++); //for debug
		LCD_SPI4_CLK_HIGH();			
	}
}
#endif
//通过 spi4 接口读一个字节数据
static uint8_t Lcd_Spi4_ReadByte(void)
{
	uint8_t i,spidat;

	spidat = 0;
	for(i = 0; i < 8; i++)			
	{  
		spidat <<= 1;
		LCD_SPI4_CLK_LOW();
		LCD_SPI4_CLK_HIGH();	
		spidat |= LCD_SPI4_MISO_GET();		
	}
	return spidat;
}
//硬件复位
static void Lcd_Spi4_HardReset(void)
{
    LCD_SPI4_RESET_HIGH();
    LCD_Delay(10);
	LCD_SPI4_RESET_LOW();
    LCD_Delay(50);
    LCD_SPI4_RESET_HIGH();
    LCD_Delay(10);
}
///////////////////////////////lcd命令接口///////////////////////////////////////////////
//写一个lcd寄存器索引值
static void Lcd_Spi4_WriteReg( uint8_t reg)
{
	LCD_DC_LOW();
	LCD_CS_LOW();
	Lcd_Spi4_WriteByte(reg);
	LCD_CS_HIGH();
}
//写寄存器的数据
static void Lcd_Spi4_WriteRegData( uint8_t data)
{
	LCD_DC_HIGH();
	LCD_CS_LOW();
	Lcd_Spi4_WriteByte(data);
	LCD_CS_HIGH();
//	LCD_DC_LOW();
}

//写寄存器及数据(一条完整的命令)
static void Lcd_Spi4_WriteCommand(uint8_t LCD_Reg, uint8_t *pRegValue,uint8_t len)
{
	uint32_t i;

	Lcd_Spi4_WriteReg(LCD_Reg);

	LCD_DC_HIGH();
	LCD_CS_LOW();
	for(i = 0; i < len; i++)
	{
		uint8_t dat = (uint8_t)*pRegValue;
		Lcd_Spi4_WriteByte(dat);
		pRegValue++;
	}
	LCD_CS_HIGH();
//	LCD_DC_LOW();
}	
//============================lcd api接口======================================
//写显示数据
static void Lcd_Spi4_WriteData16(HCOLOR *psrc,uint32_t len)
{
	uint32_t u8Len = len;
	
	LCD_DC_HIGH();
	LCD_CS_LOW();
	while(u8Len--)
	{
		uint8_t h,l;
		uint16_t d;
		HCOLOR color;
        
#if GUI_COLOR_DEPTH == GUI_COLOR_24BIT
		color = *psrc++;
		d = ((((uint16_t)(GET_COLOR_R(color) >> 3)) << 11) | (((uint16_t)(GET_COLOR_G(color) >> 2)) << 5) | ((uint16_t)(GET_COLOR_B(color) >> 3)));
#elif GUI_COLOR_DEPTH == GUI_COLOR_16BIT 
		d = *psrc++;
#endif

		h = (uint8_t)((d >> 8) & 0xFF);	
		Lcd_Spi4_WriteByte(h);		//先写高8bit
		l = (uint8_t)(d  & 0xFF);
		Lcd_Spi4_WriteByte(l);		//再写低8bit
	}
	LCD_CS_HIGH();	
}
static void Lcd_Spi4_WriteData18(HCOLOR *psrc,uint32_t len)
{
	uint32_t u8Len = len;
	
	LCD_DC_HIGH();
	LCD_CS_LOW();
	while(u8Len--)
	{
		uint8_t r,g,b;
		HCOLOR color;
		
		color = *psrc++;
#if GUI_COLOR_DEPTH == GUI_COLOR_24BIT
		r = GET_COLOR_R(color);
		g = GET_COLOR_G(color);
		b = GET_COLOR_B(color);
#endif
		Lcd_Spi4_WriteByte(r);
		Lcd_Spi4_WriteByte(g);
		Lcd_Spi4_WriteByte(b);
	}
	LCD_CS_HIGH();	
}
static void Lcd_Spi4_WriteData24(HCOLOR *psrc,uint32_t len)
{
}
//写同一个颜色的显示数据
static void Lcd_Spi4_WriteColor16(HCOLOR color,uint32_t len)
{
	uint8_t h,l;
	uint16_t d;

#if GUI_COLOR_DEPTH == GUI_COLOR_24BIT
	d = ((((uint16_t)(GET_COLOR_R(color) >> 3)) << 11) | (((uint16_t)(GET_COLOR_G(color) >> 2)) << 5) | ((uint16_t)(GET_COLOR_B(color) >> 3)));
	h = (uint8_t)((d >> 8) & 0xFF);	
	l = (uint8_t)(d  & 0xFF);
#elif GUI_COLOR_DEPTH == GUI_COLOR_16BIT 
	h = (uint8_t)((color >> 8) & 0xFF);	
	l = (uint8_t)(color  & 0xFF);
#endif
    
	LCD_DC_HIGH();
	LCD_CS_LOW();
	while(len--)
	{
		Lcd_Spi4_WriteByte(h);		//先写高8bit
		Lcd_Spi4_WriteByte(l);		//再写低8bit
	}	
	LCD_CS_HIGH();	
}
//写同一个颜色的显示数据
static void Lcd_Spi4_WriteColor18(HCOLOR color,uint32_t len)
{
	uint8_t r,g,b;
#if GUI_COLOR_DEPTH == GUI_COLOR_24BIT
	r = GET_COLOR_R(color);
	g = GET_COLOR_G(color);
	b = GET_COLOR_B(color);
#endif
	LCD_DC_HIGH();
	LCD_CS_LOW();
	while(len--)
	{
		Lcd_Spi4_WriteByte(r);
		Lcd_Spi4_WriteByte(g);
		Lcd_Spi4_WriteByte(b);
	}	
	LCD_CS_HIGH();	
}
static void Lcd_Spi4_WriteColor24(HCOLOR color,uint32_t len)
{
}
//休眠进入和唤醒
void Lcd_Spi4_SleepInOut(bool sleep)
{
//	if(sleep) //sleep in
//	{
//	}
//	else //sleep out
//	{
//	}
}
static void Lcd_Spi4_SetWindow(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1)
{
	__ALIGNED(4) uint8_t buffer[4];

	x0 += LcdXOffset;
	x1 += LcdXOffset;
	y0 += LcdYOffset;
	y1 += LcdYOffset;
	
	buffer[0] = (uint8_t)(x0 >> 8);
	buffer[1] = (uint8_t)(x0);
	buffer[2] = (uint8_t)((x1 - 1) >> 8);
	buffer[3] = (uint8_t)(x1 - 1);
	Lcd_Spi4_WriteCommand(0x2a,buffer,4);

	buffer[0] = (uint8_t)(y0 >> 8);
	buffer[1] = (uint8_t)(y0);
	buffer[2] = (uint8_t)((y1 - 1) >> 8);
	buffer[3] = (uint8_t)(y1 - 1);
	Lcd_Spi4_WriteCommand(0x2b,buffer,4);
	
	Lcd_Spi4_WriteReg(0x2c);
	
}
//读寄存器数据
//regIndex: 寄存器索引
//pRegData: 保存返回数据
//regNum: 要读的数据字节数
static void Lcd_Spi4_ReadReg(uint8_t regIndex,uint8_t *pRegData,uint8_t regNum)
{
	Lcd_Spi4_WriteReg(regIndex);

	LCD_CS_LOW();
	LCD_DC_HIGH();
	for(uint32_t i = 0; i < regNum;i++)
		pRegData[i] = Lcd_Spi4_ReadByte();
	LCD_CS_HIGH();
}
//背光控制
void Lcd_Spi4_BackLightSet(uint8_t duty)
{
    if(LCD_BACKLIGHT_ON == duty)
        LCD_SPI4_BK_ON();
    else if(LCD_BACKLIGHT_OFF == duty)
        LCD_SPI4_BK_OFF();
//    else
//        //setpwm(duty);
}
void Lcd_RegInterface_Spi4_16(DRVLCD *pLcd,uint16_t xOffset,uint16_t yOffset)
{
	Lcd_Spi4_IoInit();
	pLcd->SetWindow		= Lcd_Spi4_SetWindow;
	pLcd->SleepInOut 	= Lcd_Spi4_SleepInOut;
	pLcd->WriteColor	= Lcd_Spi4_WriteColor16;
	pLcd->WriteData		= Lcd_Spi4_WriteData16;
	pLcd->Reset				    = Lcd_Spi4_HardReset;
	pLcd->BkSet				    = Lcd_Spi4_BackLightSet;
	pLcd->WriteIndexReg			= Lcd_Spi4_WriteReg;
	pLcd->WriteRegParameter		= Lcd_Spi4_WriteRegData;
	pLcd->WriteRegAndParameter 	= Lcd_Spi4_WriteCommand;
	pLcd->ReadReg				= Lcd_Spi4_ReadReg;
	LcdXOffset = xOffset;
	LcdYOffset = yOffset;
}

void Lcd_RegInterface_Spi4_18(DRVLCD *pLcd,uint16_t xOffset,uint16_t yOffset)
{
	Lcd_RegInterface_Spi4_16(pLcd,xOffset,yOffset);
	pLcd->WriteColor	= Lcd_Spi4_WriteColor18;
	pLcd->WriteData		= Lcd_Spi4_WriteData18;
}
void Lcd_RegInterface_Spi4_24(DRVLCD *pLcd,uint16_t xOffset,uint16_t yOffset)
{
	Lcd_RegInterface_Spi4_16(pLcd,xOffset,yOffset);
	pLcd->WriteColor	= Lcd_Spi4_WriteColor24;
	pLcd->WriteData		= Lcd_Spi4_WriteData24;
}
/************************END OF FILE*************************************/


